Mastering Ethereum 6章 トランザクション
トランザクションの構造
Nonce
EOAによって発行されるシークエンスの番号。トランザクションの重複をしないようにする
Gas Price
Gas limit
Recipient
受け手のアドレス
Value
送料
Data
データ量
v,r,s
EOAを楕円暗号曲線で暗号化した値
トランザクションはRecursive Length Prefix encoding schemeによって番号付けがされる。これは8bits。
Nonce
nonce: A scalar value equal to the number of transactions sent from this address or, in the case of accounts with associated code, the number of contract-creations made by this account.
だいたいトランザクション番号通りにブロックに格納されるようにするという点と、トランザクションが複製できないようにするという点でNonceは大事。
例えば、6ETH送ってすぐに8ETH送る。あるノードは6ETHを先に受け取って、あるノードは8ETHを先に受け取った。しかし、10ETHしか持っていなかった場合、Nonceなしにはノードはどちらのトランザクションを受け取るのかわからなくなってしまう。
Nonceの取得方法
> web3.eth.getTransactionCount("0x9e713963a92c02317a681b9bb3065a8249de124f")
40
これは40番目のトランザクションという意味。
番号はペンディングトランザクションを反映しなく、Confirmされたトランザクションのみカウントする。
Nonce 0のトランザクションの次にNonce 2のトランザクションを送ると、ネットワークはNonce 1のトランザクションがまだ到達しいていないと思いこむので、Nonce 2のトランザクションは格納されない。Nonce 1のトランザクションを発行すると、やっとNonce 2のトランザクションが格納される。
トランザクションGas
ETH Gas StationがGasに関する情報を提供してくれている。
gasPriceのミニマムは0。キャパシティーによっては一生ブロックに格納されないかもしれないが、プロトコルでgas0は禁止されていない。いくつかのトランザクションは0でも格納されている。
Web3インターフェースはgasPriceを自動で計算している。
> web3.eth.getGasPrice(console.log)
> null BigNumber { s: 1, e: 10, c: [ 10000000000 ] }
gasLimitのデフォルトは21,000 gas
> web3.eth.getGasPrice(function(err, res) {console.log(res*21000)} )
> 210000000000000
Recipient
20bytesのEthereumアドレス。
Transaction Value and Data
ValueとData、Dataだけ、Valueだけ、両方なしというのもありうる。
ValueだけのトランザクションはPayment。DataだけのトランザクションはInvocation。両方ないのはただのgasの消費。
トランザクションをコントラクトに送った場合、EVMでそのコントラクトを実行し、トランザクションのDataで指定されているFunctionを実行する。Dataがない場合、EVMはfallback functionを実行する。functionがpayableであればコントラクト実行可能。なければ、contractの残高を更新する。
DataではA function selectorとThe function argumentsを指定している。
withdraw(uint256)というfunctionがあった時に、
> web3.sha3("withdraw(uint256)");
'0x2e1a7d4d13322e7b96f9a57413e1525c250fb7a9021cf91d1540d5b69f16a49f'
そのfunctionをハッシュ化して、でてきた値の、最初の4bytes0x2e1a7d4dがfunction selector
コントラクトを作成するトランザクションでは0x000000000000000000000000000000000000dEaDにトランザクションを送る。その際にはDataが必要。Valueだけで送信するとburnと同等の効果。
code:javascript
$ solc --bin Faucet.sol
Binary:
6060604052341561000f57600080fd5b60e58061001d6000396000f30060606040526004361060...
src = web3.eth.accounts0;
faucet_code = \
"0x6060604052341561000f57600080fd5b60e58061001d6000396000f300606...f0029";
web3.eth.sendTransaction({from: src, to: 0, data: faucet_code, \
gas: 113558, gasPrice: 200000000000});
"0x7bcc327ae5d369f75b98c0d59037eec41d44dfae75447fd753d9f2db9439124b"
これでEthereumにデプロイ完了。
code:javascript
eth.getTransactionReceipt( \
"0x7bcc327ae5d369f75b98c0d59037eec41d44dfae75447fd753d9f2db9439124b");
{
blockHash: "0x6fa7d8bf982490de6246875deb2c21e5f3665b4422089c060138fc3907a95bb2",
blockNumber: 3105256,
contractAddress: "0xb226270965b43373e98ffc6e2c7693c17e2cf40b",
cumulativeGasUsed: 113558,
from: "0x2a966a87db5913c1b22a59b0d8a11cc51c167a89",
gasUsed: 113558,
logs: [],
logsBloom: \
"0x00000000000000000000000000000000000000000000000000...00000",
status: "0x1",
to: null,
transactionHash: \
"0x7bcc327ae5d369f75b98c0d59037eec41d44dfae75447fd753d9f2db9439124b",
transactionIndex: 0
}
デジタル署名
デジタル署名の作成
S i g = F sig ( F keccak256 ( m ) , k )
k :プライベートキー
m :RLP-encoded transaction
F keccak256:ハッシュ関数
Fsig:署名アルゴリズム
Sig:作成されたデジタル署名
S i g = ( r , s )
ハッシュ関数でrとsを作り出し、これがSigになる。
トランザクションの署名
有効なトランザクションとするためには、メッセージに楕円暗号曲線のアルゴリズムを使い署名をしなければいけない。
トランザクションに署名するとは、 RLP-serialized transaction dataをKeccak-256 でハッシュ化したものに署名をするということ。
nonce, gasPrice, gasLimit, to, value, data, chainID, 0, 0が含まれたトランザクションデータを作成する
それを基に、RLP-encoded serialized messageを作成
Keccak-256 でハッシュ化する
ECDSA signatureを計算しEOAにプライベートキーで署名する
v,r,sの3つの値を作成し、トランザクションと一緒に送信
トランザクションの署名このgithubを参考に
$ node raw_tx_demo.js
RLP-Encoded Tx: 0xe6808609184e72a0008303000094b0920c523d582040f2bcb1bd7fb1c7c1...
Tx Hash: 0xaa7f03f9f4e52fcf69f836a6d2bbc7706580adce0a068ff6525ba337218e6992
Signed Raw Transaction: 0xf866808609184e72a0008303000094b0920c523d582040f2bcb1...
EIP-155で改善が提案されている。
署名後のプロセス
トランザクションの作成、署名、ブロードキャストはweb3.eth.sendTransactionのシングルオペレーションで行われる。
セキュリティーの観点から2つにこのプロセスを2つに分けて行ったほうが安全。$ node raw_tx_demo.jsの後にweb3.eth.sendSignedTransactionでネットワークにトランザクションを流す。
2つに分けることによりオフラインでのプライベートキー署名、オンラインでのブロードキャストが可能になる。
https://gyazo.com/07c3c208f8decd9175dab10f12f89b5b
Create an unsigned transaction on the online computer where the current state of the account, notably the current nonce and funds available, can be retrieved.
Transfer the unsigned transaction to an "air-gapped" offline device for transaction signing, e.g., via a QR code or USB flash drive.
Transmit the signed transaction (back) to an online device for broadcast on the Ethereum blockchain, e.g., via QR code or USB flash drive.